package com.citywithincity.compress;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.zip.GZIPInputStream;

import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;

import com.citywithincity.utils.IoUtil;


public class GzipArchive implements Archive {

	GzipArchive(){
		
	}
	
	@Override
	public void compress(String dir, String destName) throws IOException {
		TarArchiveOutputStream zaos = null;
		File gzFile = new File(destName + ".tar");
		try {
			zaos = new TarArchiveOutputStream(new FileOutputStream(gzFile));
			addFiles(zaos, new File(dir).listFiles(), "");
		} finally {
			if (zaos != null) {
				zaos.close();
			}
		}
		GzipCompressorOutputStream outputStream;
		outputStream = new GzipCompressorOutputStream(new FileOutputStream(gzFile + ".gz"));
		FileInputStream is = new FileInputStream(gzFile);
		try {
			IoUtil.copy(is, outputStream);
		} catch (Exception e) {
			try {
				is.close();
			} catch (Exception ex) {
			}
			try {
				outputStream.close();
			} catch (Exception ex) {
			}
		}
	}

	public static void addFiles(TarArchiveOutputStream zaos, File[] files, String basePath) throws IOException {
		for (File file : files) {
			if (file.isDirectory()) {
				addFiles(zaos, file.listFiles(), basePath + File.separator + file.getName());
			} else {
				TarArchiveEntry zipArchiveEntry = new TarArchiveEntry(file);
				zipArchiveEntry.setName(basePath + File.separator + file.getName());
				zaos.putArchiveEntry(zipArchiveEntry);
				InputStream is = null;
				try {
					is = new FileInputStream(file);
					IoUtil.copy(is, zaos);
					zaos.closeArchiveEntry();
				} finally {
					if (is != null)
						is.close();
				}
			}

		}
	}

	@Override
	public void decompress(String src, String destDir, List<File> files) throws IOException {
		ArchiveInputStream in = null;
		BufferedInputStream bis = null;
		File dir = new File(destDir);
		dir.mkdir();
		StringBuilder sb = new StringBuilder(destDir);
		if(!destDir.endsWith(File.separator)){
			sb.append(File.separator);
		}
		int len = sb.length();
		try {
			GZIPInputStream gis = new GZIPInputStream(new FileInputStream(src));
			in = new TarArchiveInputStream(gis);
			bis = new BufferedInputStream(in);
			TarArchiveEntry entry = (TarArchiveEntry) in.getNextEntry();
			while (entry != null) {
				String name = entry.getName();
				sb.append(name);
				if (name.endsWith("/")) {
					new File(name).mkdirs();
				} else {
					File file = new File(sb.toString());
					file.getParentFile().mkdir();
					BufferedOutputStream bos = null;
					try{
						bos = new BufferedOutputStream(new FileOutputStream(file));
						IoUtil.copy(bis, bos);
					}finally{
						if(bos!=null){
							try{bos.close();}catch(Exception e){}
						}
					}
					
					files.add(file);
				}
				sb.setLength(len);
				entry = (TarArchiveEntry) in.getNextEntry();
			}
		} finally {
			if (null != bis) {
				try {
					bis.close();
				} catch (IOException e) {

				}
			}

		}
	}

}
